package 二分查找;

/**
 * 33. 搜索旋转排序数组
 * 整数数组 nums 按升序排列，数组中的值 互不相同 。
 *
 * 在传递给函数之前，nums 在预先未知的某个下标 k（0 <= k < nums.length）上进行了 旋转，使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]]（下标 从 0 开始 计数）。例如， [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。
 * 给你 旋转后 的数组 nums 和一个整数 target ，如果 nums 中存在这个目标值 target ，则返回它的下标，否则返回 -1 。
 * 你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。
 *
 * 思路：还是采用二分查找的方式，关键点在于确定哪一部分是有序的，并根据目标值的位置调整搜索的范围.
 *
 * 解题思路：
 *  1：初始化指针：设置左右指针left 和 right分别指向数组的起始以及末尾；
 *  2：二分查找：循环，直到left > right，则退出循环；
 *  3：中间位置：计算中间索引mid。、
 *  4：直接命中：若nums[mid]等于目标值，直接返回mid。
 *  5：判断有序部分：
 *      左边部分有序，若若nums[left] <= nums[mid]，检查目标值是否在左半部分的范围内。如果是，调整right到mid-1，否则调整left到mid+1。
 *      右边部分有序，若否则检查目标值是否在右半部分的范围内。如果是，调整left到mid+1，否则调整right到mid-1。
 *  6：未找到处理：循环结束后仍未找到则返回-1。
 */
public class L_33 {

    public int search(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        while (left <= right){
            int mid = left + (right - left) / 2;
            // 如果条件命中，直接返回
            if (nums[mid] == target){
                return mid;
            }
            // 如果左半部分小于中间值，证明左半部分是有序的，基于此条件继续进行二分查找
            if (nums[left] <= nums[mid]){
                if (nums[left] <= target && target <= nums[mid]){
                    right = mid - 1;
                }else {
                    left = mid + 1;
                }
            }else { // 右半部分是有序的
                // 如果在右半部分范围内，则继续二分查找
                if (nums[mid] < target && target <= nums[right]){
                    left = mid + 1;
                }else {
                    right = mid - 1;
                }
            }
        }
        return -1;
    }
}
